import axios, { Canceler, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
import {
    INIT_STATE,
    FETCH_REFRESH_TOKEN,
    SAVE_LAST_FETCHED_TIME,
    FETCH_TENANT_TOKEN,
} from '@/reducers/common'
import { message } from 'antd'
const appKey = ''
import { store } from '@/store'
import { push } from 'redux-first-history'
import { dispatchWithPromise } from '@/utils/util'
import DefaultConfig from '../../config.default'
import config from '../../config.default'
const cancelToken = axios.CancelToken

const BASE_URL = () => {
    if (process.env.CUSTOM_NODE_ENV === 'production') {
        return DefaultConfig.request.prefix.prod//线上
    } else if (process.env.CUSTOM_NODE_ENV === 'development') {
        return DefaultConfig.request.prefix.test //测试
    }
}
//token最长有效时效两个小时，单位秒
const maxExpiresIn = DefaultConfig.loginPermissions.maxExpiresIn

//过滤特定的接口地址，以下路径不进入重复取消队列
const API_whiteList: string[] = DefaultConfig.request.common.whiteList

//特定的code状态码(code!=1)执行的操作
const specifyCodeHandles = (code: number) => {
    switch (code) {
        case 10006:
            store.dispatch({ type: INIT_STATE })
            store.dispatch(push('/login'))
            localStorage.clear()
            break;
        case 10004:
            store.dispatch({ type: INIT_STATE })
            store.dispatch(push('/login'))
            localStorage.clear()
            break;
        default:
            break;

    }
}
//特定接口不需要走刷新token接口时机判断
const specifyApiInOutOfRefreshingCode = ['/admin/user/refresh-token']


//新增axios实例

const axiosInstance = axios.create({
    baseURL: BASE_URL(),
    headers: {
        'Content-Type': 'application/json',
        // 'X-App-Key': appKey,
        // 'Access-Control-Allow-Origin': '*',
        // 'Access-Control-Allow-Credentials': true
    },
    // withCredentials: true,
    timeout: 10000,

})
const pendingList: { u: string; f: Canceler }[] = []
const removePending = (config: any) => {
    //取消重复的请求
    for (let p = 0; p < pendingList.length; p++) {
        if (pendingList[p].u === config.url + '&' + config.method) {
            pendingList[p].f()
            pendingList.splice(p, 1)
        }
    }
}
const commonRequest = async (req: InternalAxiosRequestConfig<any>) => {
    //定义请求报文
    // removePending(req)
    req.cancelToken = new cancelToken((c) => {
        if (req.url && API_whiteList.indexOf(req.url) == -1) {
            pendingList.push({ u: req.url + '&' + req.method, f: c })
        }
    })
    if (config.loginPermissions.enable) {
        const common = JSON.parse(JSON.stringify(store.getState().common))
        const { loginInfo, lastFetchedTime, tenantInfo } = common || {}
        if (typeof loginInfo !== 'boolean' && loginInfo) {
            let { accessToken, refreshToken, expiresIn } = loginInfo
            //如果租户存在就用租户token权限
            if (typeof tenantInfo != 'boolean' && tenantInfo) {
                accessToken = tenantInfo.accessToken
                refreshToken = tenantInfo.refreshToken
                expiresIn = tenantInfo.expiresIn
            }
            req.headers.Authorization = `${accessToken}`
            if (lastFetchedTime) {
                const currentTime = new Date().getTime() / 1000

                if (req.url && !specifyApiInOutOfRefreshingCode.includes(req.url)) {
                    if (currentTime - lastFetchedTime / 1000 >= maxExpiresIn) {
                        //超出token保存的最大有效时效就登出
                        store.dispatch({ type: INIT_STATE })
                        store.dispatch(push('/login'))
                        localStorage.clear()
                    } else if (currentTime - lastFetchedTime / 1000 >= Number(expiresIn)) {
                        //达到过期时效就刷新当前token
                        const result: any = await dispatchWithPromise({
                            type: FETCH_REFRESH_TOKEN,
                            payload: { refreshToken: loginInfo.refreshToken },
                        })
                        let { accessToken } = result
                        //如果租户在就调租户的刷新token机制
                        if (typeof tenantInfo != 'boolean' && tenantInfo) {
                            const resultTenant: any = await dispatchWithPromise({
                                type: FETCH_TENANT_TOKEN,
                                payload: {
                                    refreshToken
                                }
                            })
                            accessToken = resultTenant.accessToken
                        }
                        req.headers.Authorization = `${accessToken}`
                    }
                }
            }
        }
    }
    if (!req.data) req.data = {}
    // req.data.appkey = appKey
    // req.data.timestamp = new Date().getTime()
    return req
}
const commonResponse = <T>(res: AxiosResponse<ResponseData<T>, any>) => {
    //         //响应报文
    return new Promise<any>((resolve, reject) => {
        removePending(res)
        if (res.status != 200) {
            message.destroy()
            message.error('网络异常')
            reject('网络异常')
        }
        const { code } = res.data
        if (Object.prototype.toString.call(res.data) == '[object Blob]') {
            const data = res.data
            if (data.size === 0) {
                message.destroy()
                message.error('数据为空')
                reject(data)
            } else {
                resolve(res)
            }
            return
        }
        if (code === 1 || code == 10860) {
            //响应之后区获取time
            store.dispatch({ type: SAVE_LAST_FETCHED_TIME, data: new Date().getTime() })
            resolve(res.data)
        } else {
            message.destroy()
            if (res.request.responseType === 'blob') {
                resolve(res.data)
                return
            } else {
                message.error(res.data.message, 1)
            }

            specifyCodeHandles(code)
            // handler && handler(resolve, reject)
            reject(JSON.stringify(res.data))
        }
    })
}
//绑定拦截器
if (DefaultConfig.request.common.enable) {

    axiosInstance.interceptors.request.use(commonRequest)
    axiosInstance.interceptors.response.use(commonResponse)
}
export default {
    post: <T>(url: string, data?: { [key: string]: React.Key | boolean | (React.Key | undefined | boolean | { [key: string]: React.Key | boolean })[] }, config?: any): Promise<ResponseData<T>> => {
        return axiosInstance<any, ResponseData<T>>({ method: "post", url, data, ...config })
    },
    get: <T>(url: string, data?: { [key: string]: React.Key | boolean | (React.Key | undefined | boolean | { [key: string]: React.Key | boolean })[] }, config?: any): Promise<ResponseData<T>> => {
        return axiosInstance<any, ResponseData<T>>({ method: "get", url, data, ...config })
    },
}
